#! /usr/bin/python

#* ========================================================================= *#
#* ------------------------------------------------------------------------- *#
##
##  \file		doc_tree.py
##  \date		Jully 2011
##  \author		TNick
##
##  \brief		This script simplifies the task of organising documentation
##
##
## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @n
## Please read ReadMe.txt and Licence.txt in root folder @n
## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @n
##
#* ------------------------------------------------------------------------- *#
#* ========================================================================= *#
##
##
##
##
#*  INCLUDES    ------------------------------------------------------------ *#

import	fileinput, string, sys
import	os
import	subprocess


#*  INCLUDES    ============================================================ *#
##
##
##
##
#*  DATA    ---------------------------------------------------------------- *#


#*  DATA    ================================================================ *#
##
##
##
##
#*  FUNCTIONS    ----------------------------------------------------------- *#

#* ------------------------------------------------------------------------- *#
def	showLogo():
	''' Simply print an informative logo at the start of the program '''

	print("===================================================")
	print("Utility for documentation management")
	print("===================================================")
	print("")

#* ========================================================================= *#

#* ------------------------------------------------------------------------- *#
def	updateFileDoxRefs( dox_file_p, prev_text, next_text ):
	''' The function updates the file with links to previous and next page

	dox_file_p - the path to check
	prev_text - reference to previous page or some link
	next_text - reference to next page or some link
	return False for failure, True for succes
	'''

	# generate new content for the links section
	new_cont = 	"\n\n" + \
				"<hr>\n" + \
				"Previous page: " + prev_text + " |\n" + \
				"Next page: " + next_text + "\n\n"

	# read the content of the file
	try:
		f = open( dox_file_p, "r" )
		dox_cont = f.read()
		f.close()
	except Exception, e:
		print ( e )
		return False

	# locate markers
	while ( True ):
		idx_st = dox_cont.find( "\\if MARKER_RING_START" )
		if ( idx_st == -1 ): break
		idx_st = dox_cont.find( "\\endif", idx_st)
		if ( idx_st == -1 ): break
		idx_st += len( "\\endif" )
		idx_end = dox_cont.find( "\\if MARKER_RING_END", idx_st )
		if ( idx_end == -1 ): break

		# only modify the file if the content changes
		if ( dox_cont[idx_st:idx_end] == new_cont ):
			return True

		# change the content
		dox_cont = dox_cont[:idx_st] + new_cont + dox_cont[idx_end:]

		# save new content
		try:
			f = open( dox_file_p, "w" )
			f.write( dox_cont )
			f.close()
		except Exception, e:
			print ( e )
			return False

		return True

	print ( "Error! Could not locate markers in " + dox_file_p + "!" )
	return False

#* ========================================================================= *#

#* ------------------------------------------------------------------------- *#
def dirEntries(dir_name, subdir, *args):
	'''Return a list of file names found in directory 'dir_name'
	If 'subdir' is True, recursively access subdirectories under 'dir_name'.
	Additional arguments, if any, are file extensions to match filenames. Matched
		file names are added to the list.
	If there are no additional arguments, all files found in the directory are
		added to the list.
	Example usage: fileList = dirEntries(r'H:\TEMP', False, 'txt', 'py')
		Only files with 'txt' and 'py' extensions will be added to the list.
	Example usage: fileList = dirEntries(r'H:\TEMP', True)
		All files and all the files in subdirectories under H:\TEMP will be added
		to the list.

	http://forums.devshed.com/python-programming-11/recursive-file-search-for-given-extension-519562.html
	'''
	fileList = []
	for file in os.listdir(dir_name):
		dirfile = os.path.join(dir_name, file)
		if os.path.isfile(dirfile):
			if not args:
				fileList.append(dirfile)
			else:
				if os.path.splitext(dirfile)[1][1:] in args:
					fileList.append(dirfile)
		# recursively access file names in subdirectories
		elif os.path.isdir(dirfile) and subdir:
			print "Accessing directory:", dirfile
			fileList.extend(dirEntries(dirfile, subdir, *args))
	return fileList
#* ========================================================================= *#

#* ------------------------------------------------------------------------- *#
def	updatePathDoxRefs( base_path, refs_list, b_recursive ):
	''' The function finds all .dox files in the folder and updates links

	base_path - the path to the folder
	refs_list - list of properly ordered references
	b_recursive - should we go down in folders?
	return False for failure, True for succes
	'''

	# if there are no entries in list there's nothing to be done
	if ( len( refs_list ) == 0 ):
		return True

	# get the list of files
	file_lst = dirEntries( base_path, b_recursive, r'dox' );

	# for each dox file in the list
	for a_file in file_lst:

		# get the name without extension; it is assumed that this is the name
		# of the page
		f_name = os.path.splitext( os.path.basename( a_file ) )[0]

		# locate this page in the list
		try:
			idx = refs_list.index( f_name )
		except Exception, e:
			print( "Warning! File " + f_name + " is not managed by the list!" )
			continue


		# special cases: first and last
		if ( idx == 0 ):
			if ( len( refs_list ) <= 1 ):
				updateFileDoxRefs( 	a_file, \
									r'\ref main', \
									r'\ref main' \
									)
			else:
				updateFileDoxRefs( 	a_file, \
									r'\ref main', \
									r'\ref ' + refs_list[idx+1] \
									)
		elif ( idx == len( refs_list )-1 ):
			updateFileDoxRefs( 	a_file, \
								r'\ref ' + refs_list[idx-1], \
								r'\ref main' \
								)
		else:
			updateFileDoxRefs( 	a_file, \
								r'\ref ' + refs_list[idx-1], \
								r'\ref ' + refs_list[idx+1] \
								)

#* ========================================================================= *#

#* ------------------------------------------------------------------------- *#
def	updateMainDox( base_path, cont_tree ):
	''' The function reads the file main.dox, replaces old tree and
	saves the result.

	base_path - the path to trunk/source
	cont_tree - the content of the tree
	return False for failure, True for succes
	'''

	# read old content
	dox_file_p = os.path.abspath( base_path + "/main.dox" )
	try:
		f = open( dox_file_p, "r" )
		dox_cont = f.read()
		f.close()
	except Exception, e:
		print ( e )
		return False

	# locate markers
	while ( True ):
		idx_st = dox_cont.find( "\\if MARKER_TREE_START" )
		if ( idx_st == -1 ): break
		idx_st = dox_cont.find( "\\endif", idx_st)
		if ( idx_st == -1 ): break
		idx_st += len( "\\endif" )
		idx_end = dox_cont.find( "\\if MARKER_TREE_END", idx_st )
		if ( idx_end == -1 ): break

		# adjust the content of the tree
		cont_tree = "\n\n" + cont_tree + "\n\n"

		# only modify the file if the content changes
		if ( dox_cont[idx_st:idx_end] == cont_tree ):
			return True

		# change the content
		dox_cont = dox_cont[:idx_st] + cont_tree + dox_cont[idx_end:]

		# save new content
		try:
			f = open( dox_file_p, "w" )
			f.write( dox_cont )
			f.close()
		except Exception, e:
			print ( e )
			return False

		return True

	print ( "Error! Could not locate markers in main.dox!" )
	return False

#* ========================================================================= *#

#* ------------------------------------------------------------------------- *#
def	doDocFolder( src_path ):

	# read the layout file
	lay_p = os.path.abspath( src_path + "/doc/DocLayout.txt" )
	try:
		f = open( lay_p, "r" )
		layout = f.read()
		f.close()
	except Exception, e:
		print ( e )
		return 0

	# generate content based on input
	crt_lev = 1
	main_dox_c = ""
	first_el = ""
	ref_list = []
	for lay_line in layout.split():
		if ( len( lay_line ) == 0 ):
			continue

		# text only
		lay_lcont = lay_line.strip()

		# comments that start with #
		if ( lay_lcont.startswith( "#" ) ):
			continue

		# get the level of this item
		it_level = 1
		for char_itr in lay_line:
			if ( char_itr != " " ):
				if ( char_itr != "\t" ):
					break
			it_level += 1
		if ( it_level > crt_lev + 1 ): it_level = crt_lev + 1

		if ( len( first_el ) == 0 ): first_el = lay_lcont
		ref_list.append( lay_lcont )

		# add content to main.dox
		main_dox_c +=  "\t" * it_level + "- "
		if ( it_level == 1 ):
			main_dox_c += "\\subpage\t"
		else:
			main_dox_c += "\\ref\t"
		main_dox_c += lay_lcont + "\n"


	# append standard footer
	main_dox_c += 	"\n\n" + \
					"<hr>\n" + \
					"Previous page: <a href=\"https:/code.google.com/p/cad-play-ground/\">Project home</a> |\n" + \
					"Next page: \\ref " + first_el + "\n\n"

	# write content to main.dox
	if ( updateMainDox( src_path, main_dox_c ) == False ): return -1

	# update the files with new links
	if ( updatePathDoxRefs( \
			src_path + os.sep + "doc", \
			ref_list, \
			True ) == False ):
		return -1
#* ========================================================================= *#

#* ------------------------------------------------------------------------- *#
def	main():
	''' Main function that is called when the module is loaded by itself

	The function attempts to find the location of the documentation.
	If it does not find it will ask the user for a path.
	'''

	# get path of documentation
	src_path = os.path.dirname( os.path.abspath( __file__ ) )
	dxy_path = os.path.abspath( src_path + "/../../tools/doxygen" )
	src_path = src_path + "/../../source"
	src_path = os.path.abspath( src_path )
	crt_path = os.getcwd()

	while( os.path.exists( src_path ) == False ):
		print( "Could not locate the path of the documentation! " )
		print( src_path + " does not exists" )
		src_path = raw_input( "Please input it yourself:" );
		if ( len( src_path ) == 0 ):
			return -1
		src_path = os.path.abspath( src_path )


	# run doxygen to generate most of the documentation
	os.chdir( dxy_path )
	return_code = subprocess.call("doxygen ./verbose.doxyfile", shell=True)
	print ( "On first run doxygen returns " + str( return_code ) )

	# run the script that generates the tree of files
	os.chdir( crt_path )
	import	tree
	tree.main()

	# adjust the files in doc folder
	doDocFolder( src_path )

	# re-run doxygen for modified files
	os.chdir( dxy_path )
	return_code = subprocess.call("doxygen ./verbose.doxyfile", shell=True)
	print ( "On second run doxygen returns " + str( return_code ) )

	#os.chdir( crt_path )
	return 0

#* ========================================================================= *#

if __name__ == "__main__":

	# present a simple logo
	showLogo()

	sys.exit( main() )

#*  FUNCTIONS    =========================================================== *#
##
##
##
##
#* ------------------------------------------------------------------------- *#
#* ========================================================================= *#
